home *** CD-ROM | disk | FTP | other *** search
/ Internet Publisher's Toolbox 2.0 / Internet Publisher's Toolbox.iso / internet / ntserver / wtsource / sockets.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-11-14  |  11.0 KB  |  422 lines

  1. /* WIDE AREA INFORMATION SERVER SOFTWARE        
  2.    No guarantees or restrictions.  See the readme file for the full standard 
  3.    disclaimer.  
  4.    5.29.90      Harry Morris, morris@think.com
  5. */
  6.  
  7. /* Copyright (c) CNIDR (see ../COPYRIGHT) */
  8.  
  9.  
  10. #ifndef lint
  11. static char *RCSid = "$Header: /archives/stelar/src/freeWAIS/freeWAIS-0.2/ir/RCS/sockets.c,v 1.2 93/07/01 19:14:22 warnock Exp $";
  12. #endif
  13. typedef struct sockaddr SOCKADDR;
  14. typedef struct sockaddr_in SOCKADDR_IN;
  15. /* Change log:
  16.  * $Log:        sockets.c,v $
  17.  * Revision 1.2  93/07/01  19:14:22  warnock
  18.  * Fix for gethostname from francois and jonathan
  19.  * 
  20.  * Revision 1.1  1993/02/16  15:05:35  freewais
  21.  * Initial revision
  22.  *
  23.  * Revision 1.23  92/05/06  17:34:41  jonathan
  24.  * Added Mach to some compiler switches.
  25.  * 
  26.  * Revision 1.22  92/04/28  15:21:14  jonathan
  27.  * Added decoding of IP address to DNS name in accept_client handler.
  28.  * 
  29.  * Revision 1.21  92/04/01  09:49:49  morris
  30.  * declared clr_socket static to stop gcc from complaining
  31.  * 
  32.  * Revision 1.20  92/03/24  10:35:32  jonathan
  33.  * Put a loop around connect in fd_connect_to_server to check if the connect
  34.  * was interrupted by a system call (usually a timer).  Retries if errno is
  35.  * EINTR.
  36.  * 
  37.  * Revision 1.19  92/02/16  12:38:22  jonathan
  38.  * Changed bzero's to memset's.
  39.  * 
  40.  * Revision 1.18  92/02/16  12:34:11  jonathan
  41.  * Removed code refering to NOINETNTOA, since we should use inet_ntoa.
  42.  * 
  43.  * Revision 1.17  92/02/12  13:48:21  jonathan
  44.  * Added "$Log" so RCS will put the log message in the header
  45.  * 
  46.  * 
  47. */
  48.  
  49. /*
  50.    Added code in fd_accept_client_connection to print source Inet address to
  51.    stderr. 
  52.    - Jonny G Fri Apr 12 1991
  53.  
  54. */
  55.  
  56. #define sockets_c
  57.  
  58. #include "sockets.h"
  59.  
  60. #ifdef NOTCPIP /* we don't have TCPIP */
  61.  
  62. void open_server (port,socket,size) long port; long* socket; long size; {}
  63. void accept_client_connection (socket,file) long socket; FILE** file; {}
  64. void close_client_connection (file) FILE* file; {}
  65. void close_server (socket) long socket; {}
  66. FILE *connect_to_server (host_name,port) char* host_name; long port; 
  67.                                   {return(NULL);}
  68. void close_connection_to_server (file) FILE* file; {}
  69.  
  70. #else /* there is TCPIP */
  71.  
  72. #include <errno.h>
  73. #include <string.h>
  74. #include "panic.h"
  75.  
  76. #if (defined(ultrix) || defined(BSD) || defined(Mach))
  77. extern int errno;
  78. #endif /* ultrix BSD or Mach */
  79.  
  80. extern char *sys_errlist[];
  81.  
  82. #ifdef WIN32
  83. char *bcopy(char*,char*,long);
  84. #endif
  85.  
  86. /* XXX
  87. still need:
  88.  non-blocking modes
  89.  special send/recieve functions? (there are now some in ui.c)
  90.  asynchronous calls?
  91. */
  92.  
  93. /* define the number of queued connections allowable on each port */
  94. #define QUEUE_SIZE 3
  95.  
  96. #ifndef WIN32
  97.  
  98. /*---------------------------------------------------------------------------*/
  99. /* Server functions                                                          */
  100. /*---------------------------------------------------------------------------*/
  101.  
  102. static boolean clr_socket _AP((struct sockaddr_in *address, long portnumber,
  103.                         long* sock));
  104.  
  105. static boolean clr_socket(address, portnumber, sock)
  106.      struct sockaddr_in *address;
  107.      long portnumber;
  108.      long *sock;
  109. {
  110.   if (errno == EADDRINUSE) {
  111.     /* Try connecting to it */
  112.     if (connect(*sock, (struct sockaddr*)address, sizeof (struct sockaddr_in)) == 0) {
  113.       close(*sock);
  114.       waislog(WLOG_HIGH, WLOG_ERROR,
  115.               "Cannot bind port %ld: (Address already in use).",
  116.               portnumber);
  117.       waislog(WLOG_HIGH, WLOG_ERROR, "waisserver is already running on this system");
  118.       panic("Exiting");
  119.     } else {
  120.       /* Connection failed; probably socket in FIN_WAIT */
  121.       int one = 1;
  122.  
  123.       (void) close(*sock);
  124.       if ((*sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
  125.         panic("Open socket failed in trying to clear the port.");
  126.       /*printf("Error binding port %d: (address already in use).\n\
  127. Attempting to clear stale socket...", portnumber);*/
  128.       if ( setsockopt(*sock, SOL_SOCKET, SO_REUSEADDR, 
  129.                       (char*)&one, sizeof (one)) < 0) {
  130.         /*printf("Warning: Setsockopt SO_REUSEADDR failed.");*/
  131.       }
  132.       address->sin_family = AF_INET;
  133.       address->sin_addr.s_addr = INADDR_ANY;
  134.  
  135.       address->sin_port = (unsigned short int)htons(portnumber);
  136.  
  137. /*      if (bind(*sock,( SOCKADDR*) address, sizeof(SOCKADDR_IN)) == 0) { */
  138.       if (bind(*sock,(struct sockaddr*) address, sizeof(*address)) == 0) {
  139.         /*printf("Successfully cleared stale EADDRINUSE error");*/
  140.       }
  141.     }
  142.   }
  143.   return(true);
  144. }
  145.  
  146.  
  147. void
  148. open_server(port,fd,size)
  149. long port;
  150. long* fd;
  151. long size;
  152. { struct sockaddr_in address;
  153.  
  154.   memset(&address, 0, sizeof(address));
  155.  
  156.   /* open the fd */
  157.   if ((*fd = socket(AF_INET,SOCK_STREAM,0)) < 0){
  158.     panic("can't get file descriptor for socket: %s", sys_errlist[errno]);
  159.   }
  160.  
  161.   address.sin_family = AF_INET;
  162.   address.sin_addr.s_addr = htonl(INADDR_ANY);
  163.   address.sin_port = (unsigned short int)htons(port);
  164.   if (bind(*fd,(struct sockaddr*)&address,sizeof(struct sockaddr)) < 0)
  165.     clr_socket(&address, port, fd);
  166.  
  167.   if (listen(*fd,QUEUE_SIZE) < 0)
  168.     panic("can't open server: %s", sys_errlist[errno]);
  169. }
  170.  
  171.  
  172.  
  173. /* This is a lower level function provided for use by the lisp version of
  174.  * this library 
  175.  * XXX should support non-blocking mode
  176.  */
  177.  
  178. #include <arpa/inet.h>
  179.  
  180. void
  181. fd_accept_client_connection(socket,fd)
  182. long socket;
  183. long* fd;
  184. { /* accept an input connection, and open a file on it */
  185.   struct sockaddr_in source;
  186.   int sourcelen;
  187. #ifdef BSD
  188.   struct in_addr {
  189.     union {
  190.       struct { u_char s_b1,s_b2,s_b3,s_b4; } S_un_b;
  191.       u_long S_addr;
  192.     } S_un;
  193.   } addr_p;
  194. #endif /* BSD */
  195.  
  196.   sourcelen = sizeof(struct sockaddr_in);
  197.  
  198.   do {
  199.     errno = 0;
  200.     *fd = accept(socket, (struct sockaddr *)&source, &sourcelen);
  201.   } while (*fd < 0 && errno == EINTR);
  202.  
  203.   if(source.sin_family == AF_INET) {
  204.     struct hostent *peer = NULL;
  205.  
  206. #ifdef __DGUX__
  207.     peer = gethostbyaddr((char *)&source.sin_addr.s_addr, 4, AF_INET);
  208. #else
  209.     peer = gethostbyaddr((struct sockaddr_in*)&source.sin_addr, 4, AF_INET);
  210. #endif
  211.  
  212.     if(peer != NULL) {
  213.       waislog(WLOG_MEDIUM, WLOG_CONNECT,
  214.               "Accepted connection from: %s [%s]",
  215.             peer ? peer->h_name : "?",
  216. #if defined(sparc) && defined(__GNUC__)
  217.               inet_ntoa(&source.sin_addr)
  218. #else
  219.               inet_ntoa(source.sin_addr)
  220. #endif                          /* sparc */
  221.               );
  222.     }
  223.     else {
  224.       waislog(WLOG_MEDIUM, WLOG_CONNECT,
  225.               "Accepted connection from: [%s]",
  226. #if defined(sparc) && defined(__GNUC__)
  227.               inet_ntoa(&source.sin_addr)
  228. #else
  229.               inet_ntoa(source.sin_addr)
  230. #endif                          /* sparc */
  231.               );
  232.     }
  233.   }
  234.   if (*fd < 0)
  235.     panic("can't accept connection");
  236. }
  237.  
  238.  
  239. /* This is the prefered C function for accepting client requests */
  240. void
  241. accept_client_connection(socket,file)
  242. long socket;
  243. FILE** file;
  244. { long fd; /* file descriptor actually used */
  245.   fd_accept_client_connection(socket,&fd);
  246.   if ((*file = fdopen(fd,"r+")) == NULL)
  247.     panic("can't accept connection");
  248. }
  249.  
  250. /* When a server wants to end the session with a client */
  251. void
  252. close_client_connection(file)
  253. FILE* file;
  254.   fclose(file);
  255. }
  256.  
  257. /* when exiting the top level server process (not the forked
  258.    server processes that come one per client).
  259.    Maybe we need to do this once per client as well.
  260. */
  261. void
  262. close_server(socket)
  263. long socket;
  264. {
  265.   close(socket);
  266. }
  267.  
  268. #endif /* !WIN32 */
  269.  
  270. /*---------------------------------------------------------------------------*/
  271. /* Client functions                                                          */
  272. /*---------------------------------------------------------------------------*/
  273.  
  274. /* This is a lower level function provided for use by the lisp version of
  275.  * this library 
  276.  * XXX should support non-blocking mode
  277.  */
  278.  
  279. #define HOSTNAME_BUFFER_SIZE 120
  280. #define MAX_RETRYS 10
  281.  
  282. boolean
  283. fd_connect_to_server(host_name,port,fd)
  284. char* host_name;
  285. long port;
  286. long* fd;
  287. {
  288.   char hostnamebuf[80];
  289.   long rc, i;
  290.   struct hostent *host;
  291.   /* struct servent *service = NULL; not used */
  292.   struct sockaddr_in name;
  293.  
  294.   memset((char *)&name, 0,sizeof (name));
  295.  
  296. #ifdef __DGUX__
  297.   name.sin_addr = inet_addr(host_name);
  298. #else
  299.   name.sin_addr.s_addr = inet_addr(host_name);
  300. #endif
  301.  
  302.   if (name.sin_addr.s_addr != -1) {
  303.     name.sin_family = AF_INET;
  304.     (void) strcpy(hostnamebuf, host_name);
  305.   }
  306.   else {
  307.     host = gethostbyname(host_name);
  308.  
  309.     if(NULL == host){
  310.       return FALSE;
  311.     }
  312.  
  313.     name.sin_family = host->h_addrtype;
  314. #ifdef h_addr
  315. #ifdef WIN32
  316.     bcopy(host->h_addr_list[0],
  317.           (char *)&name.sin_addr, host->h_length);
  318. #else
  319.     bcopy(host->h_addr_list[0],
  320.           (caddr_t)&name.sin_addr, host->h_length);
  321. #endif
  322. #endif
  323.     (void) strcpy(hostnamebuf, host->h_name);
  324.   }
  325.   host_name = hostnamebuf;
  326.  
  327. #ifdef WIN32
  328.   name.sin_port = (unsigned short int)htons((u_short)port);
  329. #else
  330.   name.sin_port = (unsigned short int)htons(port);
  331. #endif
  332.  
  333.   *fd = socket (AF_INET, SOCK_STREAM, 0);
  334.   for(i = 0; i < MAX_RETRYS; i++) {
  335.     rc = connect (*fd, (struct sockaddr *)&name, sizeof (name));
  336.     if(rc == 0) return TRUE;
  337.     else if(errno == EINTR){
  338. #ifdef WIN32
  339.       Sleep(1000);   /* WIN32's sleep has an unit in millisec */
  340. #else
  341.       sleep(1);
  342. #endif
  343.     }
  344.     else {
  345.       perror("Connect to socket did not work (1)");
  346.       return FALSE;
  347.     }
  348.   }
  349.   return FALSE;
  350. }
  351.  
  352. /* This is the prefered C function for initiating client requests */
  353. FILE *
  354. connect_to_server(host_name,port)
  355. char* host_name;
  356. long port;
  357. {
  358.   FILE* file;
  359.   long fd;
  360.   if(fd_connect_to_server(host_name,port,&fd) == FALSE) {
  361.     perror("Connect to socket did not work (2)");
  362.     return NULL;
  363.   }
  364.  
  365.   if ((file = fdopen(fd,"r+")) == NULL) {
  366.     perror("Connect to socket did not work (3)");
  367.     return NULL;
  368.   }
  369.  
  370.   return file;
  371. }
  372.  
  373. void
  374. close_connection_to_server(file)
  375. FILE* file;
  376. {
  377.   fclose(file);
  378. }
  379.  
  380. /*---------------------------------------------------------------------------*/
  381.  
  382. #endif /* there is TCPIP */
  383.  
  384. #ifndef WIN32
  385.  
  386. /* Francois and Jonathan Goldman - hostname fix */
  387. char *
  388. mygethostname(hostname, len)
  389. char *hostname;
  390. long len;
  391. {
  392.         char    name[255];
  393.         struct  hostent *h;
  394.  
  395.         gethostname(name, 254);
  396.         strcpy(hostname,name);
  397.  
  398.         h = gethostbyname(name);
  399.  
  400.         if ( (h = gethostbyname(name)) != NULL) {
  401.                 if ( (strlen(h->h_name) >= len) && ( len > 0 ) ) {
  402.                         strncpy(hostname, h->h_name,len-1);
  403.                 }
  404.                 else {
  405.                         strcpy(hostname, h->h_name);
  406.                 }
  407.         }
  408.         else {
  409.                 if ( ( strlen(name) >= len) && (len > 0 ) ) {
  410.                         strncpy(hostname, name, len-1);
  411.                 }
  412.                 else {
  413.                         strcpy(hostname, name);
  414.                 }
  415.         }
  416.  
  417.         return(hostname);
  418. }
  419.  
  420. #endif /* !WIN32 */
  421.